/**
 * 
 */
package coop.tecso.core.test.factory;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

/**
 * A factory to create instances of {@code T}
 * 
 * @author daniel
 */
public interface GenericFactory {

    /**
     * Creates and returns a completly functional instance of {@code clazz}
     * 
     * @param clazz
     *            - the clazz of the instance returned
     * @return an instance of clazz
     */
    <T> T getNewInstance(Class<T> clazz);

    /**
     * Creates and returns {@code number} instances of {@code clazz}.
     * <p>
     * In total {@code number} instances are created.
     * </p>
     * <p>
     * If {@code shouldBeDistinct} then the instances are guaranteed to be distinct from each other.
     * </p>
     * <p>
     * What distinct actually means is implementation dependent.
     * </p>
     * 
     * @param clazz
     *            - the clazz of the instances returned
     * @param number
     * @param shouldBeDistinct
     * @return
     */
    <T> Collection<T> getNewInstances(Class<T> clazz, int number, MultipleInstanceStrategy multipleInstanceStrategy);

    /**
     * Creates and returns {@code number} instances of T.
     * <p>
     * Equivalent to {@link #getNewInstances(int, boolean)} with {@code shouldBeDistinct} in true
     * </p>
     * 
     * @param clazz
     *            - the clazz of the instances returned
     * @param number
     * @return
     */
    <T> Collection<T> getNewInstances(Class<T> clazz, int number);

    /**
     * Creates and returns a completly functional instance of T
     * <p>
     * If {@code overrides} has any entries the factory will use the object associated to the attribute name,
     * key of the entry, instead of an ad-hoc object.
     * </p>
     * 
     * @param clazz
     *            - the clazz of the instance returned
     * @param overrides
     * @return an instance of T
     */
    <T> T getNewInstance(Class<T> clazz, Map<String, Object> overrides);

    /**
     * Creates and returns a completly functional instance of T
     * <p>
     * If {@code reusables} has any entries the factory will create a handler for the reusable class and the
     * handler will always respond with the same instance (a singleton effectively) whenever it's asked to
     * handle a property.
     * </p>
     * </p>
     * 
     * @param clazz
     *            - the clazz of the instance returned
     * @param overrides
     * @return an instance of T
     **/
    <T> T getNewInstance(final Class<T> clazz, final Set<Class<?>> reusables);

    /**
     * Creates and returns a completly functional instance of T
     * <p>
     * If {@code reuses} has any entries the factory will create and reuse the object associated to the
     * attribute name, entry of the list, for all other objects that require an instance of such object.
     * </p>
     * <p>
     * If {@code overrides} has any entries the factory will use the object associated to the attribute name,
     * key of the entry, instead of an ad-hoc object.
     * </p>
     * 
     * @param clazz
     * @param reuses
     * @param overrides
     * @return
     */
    <T> T getNewInstance(Class<T> clazz, Set<Class<?>> reuses, Map<String, Object> overrides);

    /**
     * Creates and returns {@code number} completly functional instances of T
     * <p>
     * If {@code reuses} has any entries the factory will create and reuse the object associated to the
     * attribute name, entry of the list, for all other objects that require an instance of such object.
     * </p>
     * 
     * @param clazz
     *            - the clazz of the instances returned
     * @param reuses
     * @param shouldBeDistinct
     * @return an instance of T
     */
    <T> Collection<T> getNewInstances(Class<T> clazz, int number, Set<Class<?>> reuses, MultipleInstanceStrategy multipleInstanceStrategy);

    /**
     * Creates and returns {@code number} completly functional instances of T
     * <p>
     * If {@code reuses} has any entries the factory will create and reuse the object associated to the
     * attribute name, entry of the list, for all other objects that require an instance of such object.
     * </p>
     * <p>
     * If {@code overrides} has any entries the factory will use the object associated to the attribute name,
     * key of the entry, instead of an ad-hoc object.
     * </p>
     * <p>
     * The overrides will always have prefference over the reused instances.
     * </p>
     * 
     * @param clazz
     *            - the clazz of the instances returned
     * @param reuses
     * @param overrides
     * @param shouldBeDistinct
     * @return an instance of T
     */
    <T> Collection<T> getNewInstances(Class<T> clazz, int number, Set<Class<?>> reuses, Map<String, Object> overrides,
            MultipleInstanceStrategy multipleInstanceStrategy);
}
